package com.evendai.sipdemo.camera

import android.annotation.SuppressLint
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Handler
import android.os.Message
import cn.dazhou.railway.monitor.camera.ISipVideoView
import com.evendai.loglibrary.Timber
import com.evendai.sipdemo.Constants
import com.evendai.sipdemo.Keys
import com.evendai.sipdemo.util.SipUtil
import com.evendai.sipdemo.util.StorageUtil
import org.doubango.ngn.NgnEngine
import org.doubango.ngn.events.NgnInviteEventArgs
import org.doubango.ngn.events.NgnInviteEventTypes.*
import org.doubango.ngn.events.NgnMediaPluginEventArgs
import org.doubango.ngn.events.NgnMediaPluginEventTypes
import org.doubango.ngn.media.NgnMediaType
import org.doubango.ngn.sip.NgnAVSession
import org.doubango.ngn.sip.NgnInviteSession.InviteState.*
import org.doubango.ngn.sip.NgnInviteSession.InviteState.EARLY_MEDIA
import org.doubango.ngn.sip.NgnInviteSession.InviteState.INCOMING
import org.doubango.ngn.sip.NgnInviteSession.InviteState.INPROGRESS
import org.doubango.ngn.sip.NgnInviteSession.InviteState.TERMINATED
import org.doubango.ngn.utils.NgnUriUtils

class SipVideoPresenterImpl(private val activity: Activity, private var sipVideoView: ISipVideoView):
    ISipVideoPresenter {

    private var sipBroadcastReceiver: BroadcastReceiver? = null
    private var blankPacketCount = 0
    private var mAVTransfSession: NgnAVSession? = null
    private var startTime = 0L
    private var avSession: NgnAVSession? = null
    /**
     * 用于发送3个空包的Handler，为什么要发送空包呢？在接通视频的时候，或者暂停视频恢复后需要发送
     * 3个空包，否则可能视频画面静止不动，就是这么神奇，官方例子就是这么写的，就照抄吧！
     */
    private var handler = @SuppressLint("HandlerLeak") object: Handler() {
        override fun handleMessage(msg: Message) {
            if (blankPacketCount++ < 3) {
                avSession?.pushBlankPacket()   // Send blank packets to open NAT pinhole(发送空白数据包以打开NAT针孔)
                Timber.e("正在推送第${blankPacketCount}个空包")
                sendBlankPacket()
            } else {
                cancelBlankPacket()
            }
        }
    }

    override fun makeCall(phoneNumber: String) {
        registerSipReceiver()
        val engine = NgnEngine.getInstance()
        val avSession = NgnAVSession.createOutgoingSession(engine.sipService.sipStack, NgnMediaType.AudioVideo) // NgnMediaType.Video 只有视频没声音
        if (avSession == null) {
            Timber.fe("NgnAVSession.createOutgoingSession()时返回null")
            sipVideoView.onInCallFail("打开视频失败")
            closeVideo()
            return
        }

        val validSipUri = SipUtil.makeValidSipUri(phoneNumber)
        avSession.remotePartyUri = validSipUri // HACK
        val makeCallSuccess = avSession.makeCall(validSipUri)
        if (!makeCallSuccess) {
            Timber.fe("avSession.makeCall()时返回false")
            sipVideoView.onInCallFail("打开视频失败")
            closeVideo()
            return
        }
        avSession.incRef()
        avSession.context = activity
        this.avSession = avSession
    }

    override fun acceptCall(avSession: NgnAVSession) {
        registerSipReceiver()
        avSession.incRef()
        avSession.context = activity
        this.avSession = avSession
        avSession.acceptCall()
        Timber.i("视频电话已接听： ${avSession.remotePartyUri}")
    }


    /** 注册Sip广播接收者，以接收Sip消息 */
    private fun registerSipReceiver() {
        if (sipBroadcastReceiver != null) return
        sipBroadcastReceiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                if (intent.action == NgnInviteEventArgs.ACTION_INVITE_EVENT) {
                    val args: NgnInviteEventArgs? = intent.getParcelableExtra(NgnInviteEventArgs.EXTRA_EMBEDDED)
                    if (args != null && args.sessionId == avSession?.id) {
                        // 会话id相同，说明通知说的就是我们这个会话。不同的通话有不同的会话id。
                        checkCallState(args, intent)
                    }
                } else if (intent.action == NgnMediaPluginEventArgs.ACTION_MEDIA_PLUGIN_EVENT) {
                    val args: NgnMediaPluginEventArgs? = intent.getParcelableExtra(NgnMediaPluginEventArgs.EXTRA_EMBEDDED)
                    if (args?.eventType == NgnMediaPluginEventTypes.STARTED_OK) {
                        Timber.i("媒体事件：args.pluginId = ${args.pluginId}")
                        val avSession = this@SipVideoPresenterImpl.avSession!!
                        var useTime = 0L
                        if (startTime == 0L) startTime = System.currentTimeMillis()
                        else useTime = System.currentTimeMillis() - startTime
                        val force = useTime >= 1000
                        Timber.i("isInCalling = ${sipVideoView.isInCalling()}, force = $force")
                        if (sipVideoView.isInCalling() && !force) return // 如果视频正在显示了，而且不是强制再次显示，则不需要处理本次的显示
                        startTime = System.currentTimeMillis()

                        avSession.setSpeakerphoneOn(Constants.sSpeakerphoneOn)              // 开启扬声器开关
                        sipVideoView.onInCall(avSession, force)                             // 通知View电话已接通
                        avSession.setRotation(avSession.compensCamRotation(true))   // 设置视频旋转角度
                        avSession.isSendingVideo = true                                     // 这只是标记一下正在发送视频了，没什么用
                        cancelBlankPacket()
                        sendBlankPacket()   // Send blank packets to open NAT pinhole(发送空白数据包以打开NAT针孔)
                    }
                }
            }
        }

        val intentFilter = IntentFilter(NgnInviteEventArgs.ACTION_INVITE_EVENT).apply {
            addAction(NgnMediaPluginEventArgs.ACTION_MEDIA_PLUGIN_EVENT)
        }
        activity.application.registerReceiver(sipBroadcastReceiver, intentFilter)
    }

    /** 查检拨号状态 */
    fun checkCallState(args: NgnInviteEventArgs, intent: Intent) {
        val avSession = this.avSession!!
        Timber.i("收到invite事件，avSession.state： ${avSession.state}")
        when (avSession.state!!) {
            NONE -> {
            }
            INCOMING, INPROGRESS, REMOTE_RINGING -> Timber.i("正在接通电话")
            EARLY_MEDIA, INCALL -> {
                NgnEngine.getInstance().soundService.stopRingTone()
                if (avSession.isLocalHeld) {
                    Timber.i("视频已暂停")
                    return
                }

                var useTime = 0L
                if (startTime == 0L) startTime = System.currentTimeMillis()
                else useTime = System.currentTimeMillis() - startTime
                val force = useTime >= 1000
                Timber.i("isInCalling = ${sipVideoView.isInCalling()}, force = $force")
                if (sipVideoView.isInCalling() && !force) return // 如果视频正在显示了，而且不是强制再次显示，则不需要处理本次的显示
                startTime = System.currentTimeMillis()

                avSession.setSpeakerphoneOn(Constants.sSpeakerphoneOn)              // 开启扬声器开关
                sipVideoView.onInCall(avSession, force)                             // 通知View电话已接通
                avSession.setRotation(avSession.compensCamRotation(true))   // 设置视频旋转角度
                avSession.isSendingVideo = true                                     // 这只是标记一下正在发送视频了，没什么用
                cancelBlankPacket()
                sendBlankPacket()   // Send blank packets to open NAT pinhole(发送空白数据包以打开NAT针孔)

                if (args.eventType == REMOTE_TRANSFER_INPROGESS) {
                    // Native code created new session handle to be used to replace the current one (event = "tsip_i_ect_newcall").
                    mAVTransfSession = NgnAVSession.getSession(args.sessionId)
                }

                Timber.i("收到invite事件，args.eventType = ${args.eventType}")
                @Suppress("NON_EXHAUSTIVE_WHEN")
                when (args.eventType) {
                    MEDIA_UPDATED -> sipVideoView.onInCall(avSession, true)
                    REMOTE_TRANSFER_NOTIFY -> {
                        val sipCode: Short = intent.getShortExtra(
                            NgnInviteEventArgs.EXTRA_SIPCODE,
                            0.toShort()
                        )
                        if (sipCode >= 300 && avSession.isLocalHeld) {
                            avSession.resumeCall()
                        }
                    }
                    REMOTE_TRANSFER_REQUESTED -> {
                        val referToUri = intent.getStringExtra(NgnInviteEventArgs.EXTRA_REFERTO_URI)
                        val referToName = NgnUriUtils.getDisplayName(referToUri)
                        if (!referToUri.isNullOrEmpty() && !referToName.isNullOrEmpty()) {
                            avSession.acceptCallTransfer()
                        }
                    }
                    REMOTE_TRANSFER_FAILED -> mAVTransfSession = null
                    REMOTE_TRANSFER_COMPLETED -> {
                        if (mAVTransfSession != null) {
                            mAVTransfSession!!.context = avSession.context
                            this.avSession = mAVTransfSession!!
                            mAVTransfSession = null
                            sipVideoView.onInCall(avSession, true)
                        }
                    }
                    else -> {

                    }
                }
            }
            TERMINATING, TERMINATED -> {
                Timber.i("通话结束")
                cancelBlankPacket()
                sipVideoView.onEndCall()
            }
        }
    }

    /** Send blank packets to open NAT pinhole(发送空白数据包以打开NAT针孔) */
    private fun sendBlankPacket() {
        handler.sendEmptyMessageDelayed(0, 250)
    }

    private fun cancelBlankPacket() {
        handler.removeCallbacksAndMessages(0)
        blankPacketCount = 0
    }

    /** 关闭视频，也就是挂断电话，释放一切资源 */
    override fun closeVideo() {
        if (sipBroadcastReceiver != null) {
            activity.application.unregisterReceiver(sipBroadcastReceiver)
            sipBroadcastReceiver = null
        }
        avSession?.hangUpCall()
        avSession?.context = null
        avSession?.decRef()
        cancelBlankPacket()
    }

    /** 改变Presenter对应的View，此方法用在复用一个视频时，Presenter不变，而视频显示在另一个地方时使用 */
    override fun changeView(sipVideoView: ISipVideoView) {
        this.sipVideoView = sipVideoView
    }

    override fun toggleSpeaker() {
        avSession?.toggleSpeakerphone()
    }

    override fun setSpeakerphoneOn(speakerOn: Boolean) {
        avSession?.setSpeakerphoneOn(speakerOn)
    }

}